//
//  BEImageExtension.swift
//  BasicExtensions
//
//  Created by Fanxx on 2018/3/23.
//  Copyright © 2018年 fanxx. All rights reserved.
//

import UIKit
import Accelerate

extension UIImage {
    ///获取当前启动页
    public static func launch() -> UIImage? {
        if let n = self.launchImageName() {
            return UIImage(named:n)
        }else{
            return nil
        }
    }
    ///获取启动页名称
    private static func launchImageName() -> String? {
        var viewSize = UIScreen.main.bounds.size
        var viewOrientation = "Portrait"
        if UIDevice.current.orientation.isLandscape {
            viewSize = CGSize(width:viewSize.height, height:viewSize.width)
            viewOrientation = "Landscape"
        }
        
        if let imagesDict = Bundle.main.infoDictionary?["UILaunchImages"] as? [[String:Any]] {
            for dict in imagesDict {
                if let ss = dict["UILaunchImageSize"] as? String,let so = dict["UILaunchImageOrientation"] as? String {
                    let imageSize = NSCoder.cgSize(for: ss)
                    if imageSize.equalTo(viewSize) && viewOrientation == so {
                        return dict["UILaunchImageName"] as? String
                    }
                }
            }
        }
        return nil
    }
    ///画图
    public static func create(size: CGSize, scale: CGFloat? = nil, drawing: (CGContext) -> Void) -> UIImage {
        if let scale = scale {
            UIGraphicsBeginImageContextWithOptions(size, false, scale)
        } else {
            UIGraphicsBeginImageContext(size)
        }
        let context = UIGraphicsGetCurrentContext()!
        drawing(context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
    ///生成虚线图
    public static func create(dottedLine color: UIColor, size: CGSize, spacing: CGFloat) -> UIImage {
        UIGraphicsBeginImageContext(CGSize(width: size.width + spacing, height: size.height + spacing))
        let context = UIGraphicsGetCurrentContext()!
        //第一行
        context.beginPath()
        context.setLineWidth(size.height)
        context.setStrokeColor(color.cgColor)
        context.setLineDash(phase: 0, lengths: [size.width,spacing])
        context.move(to: CGPoint(x: 0, y: size.height / 2))
        context.addLine(to: CGPoint(x: size.width + spacing, y: size.height / 2))
        context.strokePath()
        //第二行
        context.setLineWidth(spacing)
        context.setStrokeColor(color.cgColor)
        context.setLineDash(phase: 0, lengths: [spacing,size.width])
        context.move(to: CGPoint(x: -size.width, y: size.height + spacing / 2))
        context.addLine(to: CGPoint(x: size.width + spacing, y: size.height + spacing / 2))
        context.strokePath()
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
    public static func create(mask text:NSAttributedString, size: CGSize = CGSize(width: 1000, height: 1000),color: UIColor = UIColor(white: 0, alpha: 0.5)) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
        let context = UIGraphicsGetCurrentContext()!
        context.setFillColor(color.cgColor)
        context.fill(CGRect(origin: .zero, size: size))
        
        let rect = text.boundingRect(with: size, options: [], context: nil)
        let point = CGPoint(x: (size.width - rect.size.width) / 2, y: (size.height - rect.size.height) / 2)
        text.draw(in: CGRect(origin: point, size: rect.size))
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
    public static func create(color: UIColor, size: CGSize = .init(1)) -> UIImage {
        if (size.width <= 0 || size.height <= 0) {
            preconditionFailure("This size: \(size) is not invalid")
        }
        let rect = CGRect(origin: .zero, size: size)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        let context = UIGraphicsGetCurrentContext()!
        context.setFillColor(color.cgColor)
        context.fill(rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
    ///裁切
    public func byClip(in rect: CGRect) -> UIImage {
        let size = CGSize(abs(rect.minX) + rect.width, abs(rect.minY) + rect.height)
        UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
        self.draw(at: -rect.origin)
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image;
    }
    ///重置大小
    public func byResize(_ size: CGSize) -> UIImage {
        if size.width <= 0 || size.height <= 0 { return self }
        return .create(size: size, scale: self.scale) { _ in
            self.draw(in: .init(size))
        }
    }
    ///重置大小
    public func byResize(_ size: CGSize, contentMode: UIView.ContentMode) -> UIImage {
        if size.width <= 0 || size.height <= 0 { return self }
        return .create(size: size, scale: self.scale) { _ in
            self.draw(in: .init(size), contentMode: contentMode, clipsToBounds: false)
        }
    }
    public func draw(in rect: CGRect, contentMode: UIView.ContentMode, clipsToBounds: Bool) {
        let drawRect = rect.fit(size: self.size, contentMode: contentMode)
        if (drawRect.size.width == 0 || drawRect.size.height == 0) { return }
        if (clipsToBounds) {
            if let context = UIGraphicsGetCurrentContext() {
                context.saveGState()
                context.addRect(rect)
                context.clip()
                self.draw(in: drawRect)
                context.restoreGState()
            }
        } else {
            self.draw(in: drawRect)
        }
    }
    /// 圆角
    public func byRoundCorner(radius: CGFloat, corners: UIRectCorner = .allCorners, borderWidth: CGFloat = 0, borderColor: UIColor? = nil, borderLineJoin: CGLineJoin = .miter) -> UIImage {
        let newCorners: UIRectCorner
        if corners != .allCorners {
            var temp: UIRectCorner = []
            if corners.contains(.topLeft) { temp.insert(.bottomLeft) }
            if corners.contains(.topRight) { temp.insert(.bottomRight) }
            if corners.contains(.bottomLeft) { temp.insert(.topLeft) }
            if corners.contains(.bottomRight) { temp.insert(.topRight) }
            newCorners = temp
        } else {
            newCorners = corners
        }
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let context = UIGraphicsGetCurrentContext()!
        let rect = CGRect(origin: .zero, size: self.size)
        context.scaleBy(x: 1, y: -1)
        context.translateBy(x: 0, y: -rect.size.height)
        
        let minSize = min(self.size.width, self.size.height);
        if (borderWidth < minSize / 2) {
            let path = UIBezierPath(roundedRect: rect.insetBy(dx: borderWidth, dy: borderWidth), byRoundingCorners: newCorners, cornerRadii: .init(radius, borderWidth))
            path.close()
            
            context.saveGState()
            path.addClip()
            context.draw(self.cgImage!, in: rect)
            context.restoreGState()
        }
        
        if let borderColor = borderColor, borderWidth < minSize / 2 && borderWidth > 0 {
            let strokeInset = (floor(borderWidth * self.scale) + 0.5) / self.scale
            let strokeRect = rect.insetBy(dx: strokeInset, dy: strokeInset)
            let strokeRadius = radius > self.scale / 2 ? radius - self.scale / 2 : 0;
            let path = UIBezierPath(roundedRect: strokeRect, byRoundingCorners: newCorners, cornerRadii: .init(strokeRadius, borderWidth))
            path.close()
            
            path.lineWidth = borderWidth
            path.lineJoinStyle = borderLineJoin
            borderColor.setStroke()
            path.stroke()
        }
        
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }
    /// 换色
    public func byTint(_ color: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let rect = CGRect(origin: .zero, size: self.size)
        color.set()
        UIRectFill(rect)
        self.draw(at: .zero, blendMode: .destinationIn, alpha: 1)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage ?? self
    }
    ///旋转图片(角度)
    public func byRotate(degrees: CGFloat) -> UIImage {
        return self.byRotate(radians: degrees.asRadians)
    }
    ///旋转图片(弧度)
    public func byRotate(radians: CGFloat) -> UIImage {
        let width = self.cgImage!.width
        let height = self.cgImage!.height
        let newRect = CGRect(x: 0, y: 0, width: width, height: height)
        newRect.applying(.init(rotationAngle: radians))
        
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo: CGBitmapInfo = [.byteOrder32Little,
                                        CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)]
        let context = CGContext(data: nil, width: Int(newRect.size.width), height: Int(newRect.size.height), bitsPerComponent: 8, bytesPerRow: Int(newRect.size.width) * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)!
        
        context.setShouldAntialias(true)
        context.setAllowsAntialiasing(true)
        context.interpolationQuality = .high
        
        context.translateBy(x: newRect.size.width * 0.5, y: newRect.size.height * 0.5)
        context.rotate(by: radians)
        
        context.draw(self.cgImage!, in: CGRect(x: -(CGFloat(width) * 0.5), y: -(CGFloat(height) * 0.5), width: CGFloat(width), height: CGFloat(height)))
        
        let imgRef = context.makeImage()
        let img = UIImage(cgImage: imgRef!, scale: self.scale, orientation: self.imageOrientation)
        return img
    }
    ///旋转图片
    public func byRotateLeft90() -> UIImage {
        self.byRotate(degrees: 90)
    }
    ///旋转图片
    public func byRotateRight90() -> UIImage {
        self.byRotate(degrees: -90)
    }
    ///旋转图片
    public func byRotate180() -> UIImage {
        self.byRotate(degrees: 180)
    }
    ///翻转图片
    private func byFlip(_ axis: NSLayoutConstraint.Axis) -> UIImage {
        guard let image = self.cgImage else {  return self }
        let width = image.width
        let height = image.height
        let bytesPerRow = width * 4
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue:
                                        CGBitmapInfo.byteOrderMask.rawValue |
                                      CGImageAlphaInfo.premultipliedFirst.rawValue)
        let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: Int(bytesPerRow), space: colorSpace, bitmapInfo: bitmapInfo.rawValue)!
        
        context.draw(image, in: .init(x: 0, y: 0, width: width, height: height))
        guard let data = context.data else {  return self }
        var src = vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
        var dest = vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
        
        if axis == .horizontal {
            vImageHorizontalReflect_ARGB8888(&src, &dest, vImage_Flags(kvImageBackgroundColorFill))
        }else{
            vImageVerticalReflect_ARGB8888(&src, &dest, vImage_Flags(kvImageBackgroundColorFill))
        }
        
        let imgRef = context.makeImage()!
        return .init(cgImage: imgRef, scale: self.scale, orientation: self.imageOrientation)
    }
    ///可拉伸
    public func byResizable(_ insets: UIEdgeInsets) -> UIImage {
        return self.resizableImage(withCapInsets: insets, resizingMode: .stretch)
    }
    /// 合并两张图片
    public func byMerge(_ other: UIImage, in rect: CGRect) -> UIImage {
        let width: CGFloat
        if rect.minX < 0 {
            width = -rect.minX + max(self.size.width, rect.width)
        } else {
            width = max(self.size.width, rect.minX + rect.width)
        }
        let height: CGFloat
        if rect.minY < 0 {
            height = -rect.minY + max(self.size.height, rect.height)
        } else {
            height = max(self.size.height, rect.minY + rect.height)
        }
        let newSize = CGSize(width, height)
        UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
        self.draw(at: .init(-min(rect.minX, 0), -min(rect.minY, 0)))
        other.draw(in: .init(max(rect.minX, 0), max(rect.minY, 0), rect.width, rect.height))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
    /// 合并两张图片
    public func byMerge(_ other: UIImage, at point: CGPoint) -> UIImage {
        return self.byMerge(other, in: .init(origin: point, size: other.size))
    }
    /// 对图片做多种处理
    public func by(_ processing: BEProcessing...) -> UIImage {
        return self.by(batch: processing)
    }
    /// 对图片做多种处理
    public func by(batch batchProcessing: [BEProcessing]) -> UIImage {
        var result = self
        batchProcessing.forEach { processing in
            switch processing {
            case .clip(let rect):
                result = result.byClip(in: rect)
            case .resize(let size, mode: let mode):
                if let mode = mode {
                    result = result.byResize(size, contentMode: mode)
                } else {
                    result = result.byResize(size)
                }
            case .corner(let radius, let corners, let borderWidth, let borderColor, let borderLineJoin):
                result = result.byRoundCorner(radius: radius, corners: corners, borderWidth: borderWidth, borderColor: borderColor, borderLineJoin: borderLineJoin)
            case .tint(let color):
                result = result.byTint(color)
            case .rotate(let radians):
                result = result.byRotate(radians: radians)
            case .flip(let axis):
                result = result.byFlip(axis)
            case .resizable(let insets):
                result = result.byResizable(insets)
            case .merger(let image, let rect):
                result = result.byMerge(image, in: rect)
            }
        }
        return result
    }
}
extension UIImage {
    /// 对图片的处理
    public enum BEProcessing {
        ///按指定的圆角裁切
        case corner(radius: CGFloat, corners: UIRectCorner, borderWidth: CGFloat, borderColor: UIColor?, borderLineJoin: CGLineJoin)
        ///裁切
        case clip(CGRect)
        ///重置大小
        case resize(CGSize, mode: UIView.ContentMode?)
        /// 换色
        case tint(UIColor)
        ///旋转图片(弧度)
        case rotate(radians: CGFloat)
        ///翻转图片
        case flip(NSLayoutConstraint.Axis)
        ///可拉伸
        case resizable(UIEdgeInsets)
        ///合并图片
        case merger(UIImage, in: CGRect)
        ///圆角
        public static func corner(_ radius: CGFloat, corners: UIRectCorner = .allCorners) -> Self {
            return .corner(radius: radius, corners: corners, borderWidth: 0, borderColor: nil, borderLineJoin: .miter)
        }
        ///圆角
        public static func corner(_ radius: CGFloat, borderWidth: CGFloat, borderColor: UIColor?, borderLineJoin: CGLineJoin = .miter) -> Self {
            return .corner(radius: radius, corners: .allCorners, borderWidth: borderWidth, borderColor: borderColor, borderLineJoin: borderLineJoin)
        }
        ///边框
        public static func corner(borderWidth: CGFloat, borderColor: UIColor?, borderLineJoin: CGLineJoin = .miter) -> Self {
            return .corner(radius: 0, corners: .allCorners, borderWidth: borderWidth, borderColor: borderColor, borderLineJoin: borderLineJoin)
        }
        ///重置大小
        public static func resize(_ size: CGSize) -> Self {
            return .resize(size, mode: nil)
        }
        ///旋转图片(角度)
        public static func rotate(_ degrees: CGFloat) -> Self {
            return .rotate(radians: degrees.asRadians)
        }
        ///合并图片
        public static func merger(_ image: UIImage, at point: CGPoint) -> Self {
            return .merger(image, in: .init(origin: point, size: image.size))
        }
    }
}
